package com.sxbbc.api.service.impl;

import java.util.Date;
import java.util.Map;

import com.sxbbc.common.core.utils.MsgUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.function.common.GetRest;
import com.function.common.RestResponse;
import com.sxbbc.api.service.ILoginService;
import com.sxbbc.common.basics.emails.SendMail;
import com.sxbbc.common.basics.enums.LoginChannelEnums;
import com.sxbbc.common.basics.exceptions.ThrowJsonException;
import com.sxbbc.common.basics.login.LoginDto;
import com.sxbbc.common.basics.login.ThirdLoginDto;
import com.sxbbc.common.basics.sms.SendSms;
import com.sxbbc.common.basics.utils.calculation.CalcuUtils;
import com.sxbbc.common.basics.utils.encrypts.pwd.Encode;
import com.sxbbc.common.basics.utils.statics.StaticUtils;
import com.sxbbc.common.basics.wx.client.WxClient;
import com.sxbbc.common.basics.wx.client.WxProgramClient;
import com.sxbbc.common.core.dto.jz.LoginRegisterVo;
import com.sxbbc.common.core.entity.jz.CCustomer;
import com.sxbbc.common.core.entity.jz.CTempWx;
import com.sxbbc.common.core.service.ICCustomerService;
import com.sxbbc.common.core.service.ICTempWxService;
import com.sxbbc.common.core.service.system.login.LoginTokenService;
import com.sxbbc.common.core.wx.WxUtils;

/**
 * 登陆注册
 *
 * @author YQQ
 */
@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private ICCustomerService customerService;
    @Autowired
    private LoginTokenService loginTokenService;
    @Autowired
    private ICTempWxService cTempWxService;

    /**
     * 发送登录验证码
     *
     * @param login 账号  （根据type）
     * @param type  1手机号   2邮箱   3账号
     * @return
     */
    @Override
    public RestResponse sendLoginCode(String login, Integer type) {
        if (type == null) {
            return GetRest.getFail("请选择登录类型");
        }
        CCustomer customer = new CCustomer();
        RestResponse restResponse = null;
        //手机号注册
        if (CalcuUtils.getInstance().isEquals(type, StaticUtils.PHONE_LOGIN)) {
            //校验用户信息
            customer.setRegisterType(StaticUtils.PHONE_LOGIN);
            customer.setPhone(login);
            customer = customerService.getCustomer(customer);
            if (customer == null) {
                return GetRest.getFail("该手机号未注册，请先注册");
            }
            //发送验证码到手机号
            restResponse = SendSms.getInstance().sendSmsAliyun(login, MsgUtils.ALI_SMS_LOGIN);
            //邮箱注册
        } else if (CalcuUtils.getInstance().isEquals(type, StaticUtils.EMAIL_LOGIN)) {
            //校验用户信息
            customer.setRegisterType(StaticUtils.EMAIL_LOGIN);
            customer.setEmail(login);
            customer = customerService.getCustomer(customer);
            if (customer == null) {
                return GetRest.getFail("该邮箱未注册，请先注册");
            }
            //发送验证码到邮箱
            restResponse = SendMail.getInstance().sendValid(login);
        }
        //发送验证码
        return restResponse;
    }

    /**
     * 登录
     * 统一登录处理
     *
     * @return
     */
    @Override
    public RestResponse doLogin(LoginRegisterVo loginVo) {
        CalcuUtils cal = CalcuUtils.getInstance();
        LoginDto loginDto = LoginDto.getInstance();
        if (cal.isEquals(loginVo.getChannel(), LoginChannelEnums.APP.getChannel())) {
            return handleAppLogin(loginVo, cal, loginDto);
        } else if (cal.isEquals(loginVo.getChannel(), LoginChannelEnums.WX.getChannel())) {
            return handleWxPublicLogin(loginVo, loginDto);
        } else if (cal.isEquals(loginVo.getChannel(), LoginChannelEnums.PC.getChannel())) {
            return handleAppLogin(loginVo, cal, loginDto);
        } else if (cal.isEquals(loginVo.getChannel(), LoginChannelEnums.WAP.getChannel())) {
            return loginTokenService.getLoginToken(loginDto, LoginChannelEnums.WAP);
        } else if (cal.isEquals(loginVo.getChannel(), LoginChannelEnums.PROGRAM.getChannel())) {
            return handleWxProgramLogin(loginVo, loginDto);
        } else {
            return GetRest.getFail("来源渠道异常");
        }
    }

    @Override
    public RestResponse handleResetPassword(LoginRegisterVo loginRegisterVo) {
        CalcuUtils calUtil = CalcuUtils.getInstance();
        CCustomer customer = new CCustomer();
        RestResponse result = null;
        //app
        if (calUtil.isEquals(loginRegisterVo.getType(), StaticUtils.PHONE_LOGIN)) {
            customer.setPhone(loginRegisterVo.getLogin());
            customer = customerService.getCustomer(customer);
            if (customer == null) {
                return GetRest.getFail("该用户不存在");
            }
            result = SendSms.getInstance().validSms(loginRegisterVo.getLogin(), loginRegisterVo.getValidCode());
            if (result != null && !result.isStatus()) {
                return result;
            }
        } else if (calUtil.isEquals(loginRegisterVo.getType(), StaticUtils.EMAIL_LOGIN)) {
            //邮箱
            customer.setEmail(loginRegisterVo.getLogin());
            customer = customerService.getCustomer(customer);
            if (customer == null) {
                return GetRest.getFail("该用户不存在");
            }
            result = SendMail.getInstance().validEmail(loginRegisterVo.getLogin(), loginRegisterVo.getValidCode());
            if (result != null && !result.isStatus()) {
                return result;
            }
        } else if (calUtil.isEquals(loginRegisterVo.getType(), StaticUtils.ACCOUNT_LOGIN)) {
            //账号
            customer.setRegisterType(StaticUtils.ACCOUNT_LOGIN);
            customer.setLogin(loginRegisterVo.getLogin());
            customer = customerService.getCustomer(customer);
            if (customer == null) {
                return GetRest.getFail("该用户不存在");
            }
        } else {
            return GetRest.getFail("来源方式异常");
        }
        String password = Encode.md5Encode(loginRegisterVo.getPassword());
        customer.setPassWord(password);
        boolean save = customerService.updateById(customer);
        if (!save) {
            throw new ThrowJsonException("重置密码失败");
        }
        return GetRest.getSuccess("重置成功");
    }

    @Override
    public RestResponse sendResetPasswordCode(LoginRegisterVo loginVo) {
        CCustomer cCustomer = new CCustomer();
        RestResponse result = null;
        if (CalcuUtils.getInstance().isEquals(loginVo.getType(), StaticUtils.PHONE_LOGIN)) {
            cCustomer.setPhone(loginVo.getLogin());
            cCustomer = customerService.getCustomer(cCustomer);
            if (cCustomer == null) {
                return GetRest.getFail("该用户不存在");
            }
            result = SendSms.getInstance().sendSmsAliyun(loginVo.getLogin(), MsgUtils.ALI_SMS_RESET_PASSWORD);
        } else if (CalcuUtils.getInstance().isEquals(loginVo.getType(), StaticUtils.EMAIL_LOGIN)) {
            cCustomer.setEmail(loginVo.getLogin());
            cCustomer = customerService.getCustomer(cCustomer);
            if (cCustomer == null) {
                return GetRest.getFail("该用户不存在");
            }
            result = SendMail.getInstance().sendValid(loginVo.getLogin());
        }
        return result;
    }

    /**
     * 处理app登陆
     *
     * @param loginVo  登陆信息
     * @param cal      工具类对象
     * @param loginDto
     * @return
     */
    private RestResponse handleAppLogin(LoginRegisterVo loginVo, CalcuUtils cal, LoginDto loginDto) {
        CCustomer customer = new CCustomer();
        //手机号登录
        if (CalcuUtils.getInstance().isEquals(loginVo.getType(), StaticUtils.PHONE_LOGIN)) {
            if (StringUtils.isEmpty(loginVo.getLogin())) {
                return GetRest.getFail("请输入手机号");
            }
            customer.setRegisterType(StaticUtils.PHONE_LOGIN);
            customer.setPhone(loginVo.getLogin());
            customer = customerService.getCustomer(customer);
            if (customer == null) {
                return GetRest.getFail("该手机号未注册，请先注册");
            }
            //校验验证码
            RestResponse restResponse = SendSms.getInstance().validSms(loginVo.getLogin(), loginVo.getValidCode());
            if (!restResponse.isStatus()) {
                return restResponse;
            }
            //邮箱登录
        } else if (cal.isEquals(loginVo.getType(), StaticUtils.EMAIL_LOGIN)) {
            if (StringUtils.isEmpty(loginVo.getLogin())) {
                return GetRest.getFail("请输入邮箱");
            }
            customer.setRegisterType(StaticUtils.EMAIL_LOGIN);
            customer.setEmail(loginVo.getLogin());
            customer = customerService.getCustomer(customer);
            if (customer == null) {
                return GetRest.getFail("该邮箱未注册，请先注册");
            }
            //校验验证码
            RestResponse restResponse = SendMail.getInstance().validEmail(loginVo.getLogin(), loginVo.getValidCode());
            if (!restResponse.isStatus()) {
                return restResponse;
            }
            //账号登录
        } else if (cal.isEquals(loginVo.getType(), StaticUtils.ACCOUNT_LOGIN)) {
            if (StringUtils.isEmpty(loginVo.getLogin())) {
                return GetRest.getFail("请输入账号");
            }
            if (StringUtils.isEmpty(loginVo.getPassword())) {
                return GetRest.getFail("密码不能为空");
            }
            customer.setRegisterType(StaticUtils.ACCOUNT_LOGIN);
            customer.setLogin(loginVo.getLogin());
            customer = customerService.getCustomer(customer);
            if (customer == null) {
                return GetRest.getFail("该账号未注册，请先注册");
            }
            String pwd = Encode.md5Encode(loginVo.getPassword());
            if (!customer.getPassWord().equals(pwd)) {
                return GetRest.getFail("密码错误");
            }
        } else {
            return GetRest.getFail("登录类型错误");
        }
        if (!CalcuUtils.getInstance().isEquals(StaticUtils.STATUS_YES, customer.getStatus())) {
            return GetRest.getFail("该用户已被冻结");
        }
        //加密 封装 存入redis
        loginDto.setChannel(LoginChannelEnums.APP.getChannel());
        loginDto.setCid(customer.getId());
        return loginTokenService.getLoginToken(loginDto, LoginChannelEnums.APP);
    }

    /**
     * 处理微信公众号登陆
     *
     * @param loginVo  登陆信息
     * @param loginDto
     * @return
     */
    private RestResponse handleWxPublicLogin(LoginRegisterVo loginVo, LoginDto loginDto) {
        // 通过code获取openid
        Map<String, String> map = WxUtils.getInstance().getWebToken(loginVo.getCode());
        String openid = map.get("openid");
        String token = map.get("access_token");
        // 通过token和openid获取微信信息
        WxClient wxclient = WxUtils.getInstance().getWebWXClient(token, openid);
        if (wxclient == null) {
            return GetRest.getFail("获取用户微信信息失败");
        }
        System.out.println("unionid：" + wxclient.getUnionid());

        CCustomer customer = null;
        // 通过unionid或openid查找用户信息
        CCustomer queryCustomer = new CCustomer();
        // 用户授权登录获取到的信息或openId为空——返回错误提示
        if (StringUtils.isBlank(wxclient.getOpenid())) {
            return GetRest.getFail("获取用户信息失败");
        }
        // 先通过openId查询用户
        queryCustomer.setOpenidWx(wxclient.getOpenid());
        customer = customerService.getCustomer(queryCustomer);


        // 如果通过openId没有查询到用户,并且获取到unionid
        // 这一步是查询小程序、app等其它关联应用有没有授权登录过
        if (customer == null && StringUtils.isNotBlank(wxclient.getUnionid())) {
            queryCustomer.setOpenidWx(null);
            queryCustomer.setUnionid(wxclient.getUnionid());
            customer = customerService.getCustomer(queryCustomer);
        }

        boolean result = false;
        // 如果有登陆授权过
        if (customer != null) {
            Boolean hasUnionId = StringUtils.isBlank(customer.getUnionid());
            Boolean hasOpenId = StringUtils.isBlank(customer.getOpenidWx());
            // 如果开始没有登录过公众号或者没有获取到unionid
            if (hasUnionId) {
                customer.setUnionid(wxclient.getUnionid());
            }
            if (hasOpenId) {
                customer.setOpenidWx(wxclient.getOpenid());
            }
            if (hasOpenId || hasUnionId) {
                result = customerService.updateById(customer);
                if (!result) {
                    throw new ThrowJsonException("登录失败");
                }
            }
            loginDto.setCid(customer.getId());
            loginDto.setChannel(LoginChannelEnums.WX.getChannel());
            loginDto.setWxopenid(customer.getOpenidWx());
            return loginTokenService.getLoginToken(loginDto, LoginChannelEnums.WX);
        } else {
            // 如果没有登陆授权过(保存信息,用于绑定账户)
            CTempWx tempWx = cTempWxService.getByMsg(wxclient.getUnionid(), wxclient.getOpenid(), LoginChannelEnums.WX.getChannel());
            if (tempWx == null) {
                tempWx = new CTempWx();
            }

            tempWx.setNickName(wxclient.getNickname());
            tempWx.setHeadUrl(wxclient.getHeadimgurl());
            tempWx.setOpenid(wxclient.getOpenid());
            tempWx.setUnionid(wxclient.getUnionid());
            tempWx.setSex(wxclient.getSex());
            tempWx.setSubscribe(wxclient.getSubscribe());
            tempWx.setSubscribeTime(new Date(wxclient.getSubscribe_time()));
            tempWx.setChannel(LoginChannelEnums.WX.getChannel());

            result = cTempWxService.saveOrUpdate(tempWx);
            if (!result) {
                throw new ThrowJsonException("获取用户信息失败");
            }
            return GetRest.getSuccess("", wxclient.getOpenid(), "bind");
        }
    }

    /**
     * 处理微信小程序登陆
     *
     * @param loginVo  登陆信息
     * @param loginDto
     * @return
     */
    private RestResponse handleWxProgramLogin(LoginRegisterVo loginVo, LoginDto loginDto) {
        String code = loginVo.getCode();
        String encryptedData = loginVo.getEncryptedData();
        String iv = loginVo.getIv();
        String sessionkey = WxUtils.getInstance().getSessionkey(code);
        WxProgramClient client = WxUtils.getInstance().getProgram(sessionkey, encryptedData, iv);
        if (client == null) {
            return GetRest.getFail("获取用户信息失败");
        }

        // 通过unionid或openid查找用户信息
        CCustomer customer = null;
        CCustomer queryCustomer = new CCustomer();
        // 用户授权登录获取到的信息或openId为空——返回错误提示
        if (StringUtils.isBlank(client.getOpenId())) {
            return GetRest.getFail("获取用户信息失败");
        }
        // 先通过openId查询用户
        queryCustomer.setOpenidProgram(client.getOpenId());
        customer = customerService.getCustomer(queryCustomer);

        // 如果通过openId没有查询到用户,并且获取到unionid
        // 这一步是查询公众号、app等其它关联应用有没有授权登录过
        if (customer == null && StringUtils.isNotBlank(client.getUnionid())) {
            queryCustomer.setOpenidProgram(null);
            queryCustomer.setUnionid(client.getUnionid());
            customer = customerService.getCustomer(queryCustomer);
        }

        boolean result = false;
        // 如果有登陆授权过
        if (customer != null) {
            Boolean hasUnionId = StringUtils.isBlank(customer.getUnionid());
            Boolean hasOpenId = StringUtils.isBlank(customer.getOpenidProgram());
            // 如果开始没有登录过小程序或者说没有获取到unionid
            if (hasUnionId) {
                customer.setUnionid(client.getUnionid());
            }
            // 如果开始是通过关联应用登录的——需要获取openid,调起支付的时候会用到
            if (hasOpenId) {
                customer.setOpenidProgram(client.getOpenId());
            }

            if (hasUnionId || hasOpenId) {
                result = customerService.updateById(customer);
                if (!result) {
                    throw new ThrowJsonException("登录失败");
                }
            }
            loginDto.setCid(customer.getId());
            loginDto.setChannel(LoginChannelEnums.PROGRAM.getChannel());
            loginDto.setProgramopenid(customer.getOpenidProgram());
            return loginTokenService.getLoginToken(loginDto, LoginChannelEnums.PROGRAM);
        } else {
            // 如果没有登陆授权过(保存信息,用于绑定账户)
            CTempWx tempWx = cTempWxService.getByMsg(client.getUnionid(), client.getOpenId(), LoginChannelEnums.PROGRAM.getChannel());
            if (tempWx == null) {
                tempWx = new CTempWx();
            }

            tempWx.setNickName(client.getNickName());
            tempWx.setHeadUrl(client.getAvatarUrl());
            tempWx.setOpenid(client.getOpenId());
            tempWx.setUnionid(client.getUnionid());
            tempWx.setSex(client.getGender());
            tempWx.setChannel(LoginChannelEnums.PROGRAM.getChannel());

            result = cTempWxService.saveOrUpdate(tempWx);
            if (!result) {
                throw new ThrowJsonException("获取用户信息失败");
            }
            return GetRest.getSuccess("", client.getOpenId(), "bind_phone");
        }
    }

    @Override
    public RestResponse validThirdLogin(ThirdLoginDto thirdLoginDto) {
        CalcuUtils calcuUtils = CalcuUtils.getInstance();
        CCustomer customer = null;
        CCustomer queryCustomer = new CCustomer();
        if (calcuUtils.isEquals(thirdLoginDto.getType(), StaticUtils.THIRD_QQ)) {
            // 第三方登录——QQ
            // QQ通过openid_qq查找是否绑定用户
            queryCustomer.setOpenidQq(thirdLoginDto.getUid());
        } else if (calcuUtils.isEquals(thirdLoginDto.getType(), StaticUtils.THIRD_WX)) {
            // 第三方登录——WX
            // WX通过union_id查找是否绑定用户
            queryCustomer.setUnionid(thirdLoginDto.getUid());
        } else {
            return GetRest.getFail("请求错误");
        }

        customer = customerService.getCustomer(queryCustomer);
        if (customer != null) {
            // 操作登陆——返回token
            LoginDto loginDto = LoginDto.getInstance();
            loginDto.setCid(customer.getId());
            loginDto.setChannel(LoginChannelEnums.APP.getChannel());
            return loginTokenService.getLoginToken(loginDto, LoginChannelEnums.APP);
        } else {
            // 用户不存在-flag返回1,需要绑定用户
            return GetRest.getSuccess("", null, "1");
        }
    }

}
